/*
 * Copyright (C) 2023  即时通讯网(52im.net) & Jack Jiang.
 * The MobileIMSDK v6.4 Project.
 * All rights reserved.
 *
 * > Github地址：https://github.com/JackJiang2011/MobileIMSDK
 * > 文档地址：  http://www.52im.net/forum-89-1.html
 * > 技术社区：  http://www.52im.net/
 * > 技术交流群：320837163 (http://www.52im.net/topic-qqgroup.html)
 * > 作者公众号：“即时通讯技术圈】”，欢迎关注！
 * > 联系作者：  http://www.52im.net/thread-2792-1-1.html
 *
 * "即时通讯网(52im.net) - 即时通讯开发者社区!" 推荐开源工程。
 *
 * ServerEventListenerImpl.java at 2023-9-22 11:44:58, code by Jack Jiang.
 */
package cn.liyao.im.event;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.liyao.im.util.ConversationUtil;
import cn.liyao.web.constant.ConversationType;
import cn.liyao.web.constant.MessageTypeU;
import cn.liyao.web.constant.ReadStatus;
import cn.liyao.web.model.*;
import cn.liyao.web.repository.*;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import server.event.ServerEventListener;
import server.network.MBObserver;
import server.processor.OnlineProcessor;
import server.protocal.Protocal;
import server.protocal.ProtocalFactory;
import server.utils.LocalSendHelper;
import sun.plugin2.message.Message;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 与客服端的所有数据交互事件在此ServerEventListener子类中实现即可。
 *
 * @author Jack Jiang
 * @version 1.0
 * @since 3.1
 */

public class ServerEventListenerImpl implements ServerEventListener {
    private static Logger logger = LoggerFactory.getLogger(ServerEventListenerImpl.class);



    private final FriendRepository friendRepository;

    private final MessageRepository messageRepository;

    private final OfflineMessageRepository offlineMessageRepository;

    private final GroupMemberRepository groupMemberRepository;

    private final ConversationRepository conversationRepository;


    private final UserRepository userRepository;

    private final GroupRepository groupRepository;

    private final ConversationUtil  conversationUtil;

    private final UserMessageRepository userMessageRepository;


    // 用来处理用户刷新页面，导致超时任务无法关闭 key (userid), map<消息ID,状态>
    private Map<String,ConcurrentHashMap<String,AtomicBoolean>>  interruptedFlags = new ConcurrentHashMap<>();


    // 正在进行中连线
    private Map<String,String> videoProgressFlags = new ConcurrentHashMap<>();


    public ServerEventListenerImpl(MessageRepository messageRepository,OfflineMessageRepository offlineMessageRepository,
                                   GroupMemberRepository groupMemberRepository,ConversationRepository conversationRepository,
                                   UserRepository userRepository,GroupRepository groupRepository,

                                   ConversationUtil  conversationUtil,FriendRepository friendRepository,    UserMessageRepository userMessageRepository) {
        this.messageRepository = messageRepository;
        this.offlineMessageRepository = offlineMessageRepository;
        this.groupMemberRepository = groupMemberRepository;
        this.conversationRepository = conversationRepository;
        this.userRepository = userRepository;
        this.groupRepository = groupRepository;
        this.friendRepository =  friendRepository;
        this.conversationUtil = conversationUtil;
        this.userMessageRepository = userMessageRepository;
    }



    @Override
    public int onUserLoginVerify(String userId, String token, String extra, Channel session) {

        logger.debug("【DEBUG_回调通知】正在调用回调方法：OnVerifyUserCallBack...(extra=" + extra + ")");
        return 0;
    }

    @Override
    public void onUserLoginSucess(String userId, String extra, Channel session) {
        logger.debug("【IM_回调通知onUserLoginSucess】用户：" + userId + " 上线了！");
    }

    @Override
    public void onUserLogout(String userId, Channel session, int beKickoutCode) {
        logger.debug("【DEBUG_回调通知onUserLogout】用户：" + userId + " 离线了（beKickoutCode=" + beKickoutCode + "）！");
        System.out.println("用户退出来");


        if(interruptedFlags.get(userId) != null){
            List<String> fps  = interruptedFlags.get(userId).keySet().stream().collect(Collectors.toList());


           for(String messageKey : fps){
               Optional<Messages> messagesDb =   messageRepository.findById(messageKey);
               Messages messagesModel =  messagesDb.get();
               JSONObject jsonObject = JSONUtil.parseObj(messagesModel.getDataContent());
               jsonObject.set("state",5);
               jsonObject.set("fp",messagesModel.getFp());
               String json = jsonObject.toJSONString(0);
               messagesModel.setDataContent(json);
               messageRepository.save(messagesModel);
           }

            interruptedFlags.remove(userId);
        }
        // 删除服务端 等待对方接听的定时任务


        if(videoProgressFlags.get(userId) != null){
                // 我掉线了，或者刷新页面了，或者重新登录了，
                Protocal protocal = ProtocalFactory.createCommonData("","0", videoProgressFlags.get(userId),true,null, MessageTypeU.VideoInterrupt.getValue());
                if (OnlineProcessor.isOnline(videoProgressFlags.get(userId))) {
                    MBObserver resultObserver = new MBObserver() {
                        public void update(boolean sucess, Object extraObj) {
                        }
                    };
                    try {
                        LocalSendHelper.sendData(protocal,resultObserver);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            videoProgressFlags.remove(userId);
            videoProgressFlags.remove(videoProgressFlags.get(userId));
        }



    }




    @Override
    public boolean onTransferMessage4C2SBefore(Protocal p, Channel session) {

        JSONObject jsonObject =  JSONUtil.parseObj(p.getDataContent());
        String groupId = jsonObject.getStr("groupId");

        GroupMember groupMember =  groupMemberRepository.findByGroupIdAndUserId(groupId, p.getFrom());
        if(groupMember == null){
            return false;
        }
        if(groupMember != null){
            if(groupMember.getUserState() == 1){
                return false;
            }
        }




        return true;
    }


    @Override
    public boolean onTransferMessage4C2S(Protocal p, Channel session) throws Exception {
        JSONObject jsonObject =  JSONUtil.parseObj(p.getDataContent());
        String groupId = jsonObject.getStr("groupId");


        if(StrUtil.isNotBlank(groupId)){
           List<GroupMember> groupMemberLit =  groupMemberRepository.findAllByGroupIdAndUserState(groupId,0);
           List<String> userIds =  groupMemberLit.stream().map(item-> item.getUserId()).collect(Collectors.toList());

            Messages messages = new Messages();
            BeanUtils.copyProperties(p,messages);
            messages.setTo(groupId);
            messageRepository.save(messages);
            conversationUtil.createMessageStatus(messages);

           for(String userId : userIds){
               jsonObject.set("from", p.getFrom());
               Protocal protocal = ProtocalFactory.createCommonData(jsonObject.toString(),"0", userId,true,null, p.getTypeu());
               OfflineMessages offlineMessages = new OfflineMessages();
               BeanUtils.copyProperties(protocal,offlineMessages);
               BeanUtils.copyProperties(protocal,messages);
               offlineMessages.setFrom(groupId);

               // 创建会话 或者修改会话
                conversationUtil.createGroupConversation(groupId,userId,p);


                   if (OnlineProcessor.isOnline(userId) && !userId.equals(p.getFrom())) {
                       LocalSendHelper.sendData(protocal,null);
                   }





           }
        }

        return true;
    }

    @Override
    public boolean onTransferMessage4C2CBefore(Protocal p, Channel session) {
        System.out.println("onTransferMessage4C2CBefore");
        Friend friend =  friendRepository.findFirstByUserIdAndFriendId(p.getTo(),p.getFrom());


        Friend friend1 =  friendRepository.findFirstByUserIdAndFriendId(p.getFrom(),p.getTo());

        if(friend.getState() == 1 || friend1.getState() == 1 ){
            // 被删除 或者我删除了
            return false;
        }

        if( friend.getBlack() == 1 || friend1.getBlack() == 1){
            // 被拉黑了 或者拉黑了
            return false;
        }


        // 通用消息需要存储 // 需要提前存储
        // 过滤掉 音视频消息  不需要处理的
       if( !(p.getTypeu() >= 50 && p.getTypeu()<= 60)){
           Messages messages = new Messages();
           BeanUtils.copyProperties(p,messages);
           Messages saveMessage =  messageRepository.save(messages);
           conversationUtil.createSelfConversation(messages);
           conversationUtil.createOtherPartyConversation(messages);
           conversationUtil.createMessageStatus(messages);
       }


        return true;
    }


    @Override
    public void onTransferMessage4C2C(Protocal p) {

        // 发送者触发取消请求
        if(p.getTypeu() == MessageTypeU.VideoCancel.getValue()){
           // 出现一个问题，取消的时候是客户端向服务器发送了一个请求，并没有记录消息ID;
            String fp = p.getDataContent();
            Optional<Messages> messages =  messageRepository.findById(fp);
            Messages model =  messages.get();

            JSONObject dataContent = JSONUtil.parseObj(model.getDataContent());
            dataContent.set("state",5);
            model.setDataContent(dataContent.toJSONString(0));
            messageRepository.save(model);
            videoProgressFlags.remove(p.getFrom());
            return;

        }
        // 发送交换信息 不做任何存储 忽略
        if(p.getTypeu() == MessageTypeU.Candidate.getValue()) return;


        // 我接受了对方的请求
        if(p.getTypeu() == MessageTypeU.VideoAnswer.getValue()){
                // 因为不需要存储消息 ，改变原有消息状体
                JSONObject jsonObject =  JSONUtil.parseObj(p.getDataContent());
                String  fp =  jsonObject.getStr("fp");
                Optional<Messages> messages =  messageRepository.findById(fp);
                Messages model =  messages.get();
                JSONObject dataContent = new JSONObject();
                dataContent.set("state",2);
                dataContent.set("start_time",System.currentTimeMillis());
                dataContent.set("answer",jsonObject.getStr("answer"));
                model.setDataContent(dataContent.toJSONString(0));
                messageRepository.save(model);
                // 用于标识 双方是否正在通话中，解决问题，用户刷新网页，断线之后无法通知对方
                videoProgressFlags.put(p.getFrom(),p.getTo());
            return;
        }

        if(p.getTypeu() == MessageTypeU.VideoRefuse.getValue()){
            // 我拒绝了对方 找到发送者按个消息iD ，改变消息状态

            String fp = p.getDataContent();
            Optional<Messages> messages =  messageRepository.findById(fp);
            Messages model =  messages.get();
            JSONObject jsonObject = JSONUtil.parseObj(model.getDataContent());
            jsonObject.set("state",3);
            jsonObject.remove("offer");
            model.setDataContent(jsonObject.toJSONString(0));
            messageRepository.save(model);
            videoProgressFlags.remove(p.getTo());
            videoProgressFlags.remove(p.getFrom());

            return;

        }

        if(p.getTypeu() == MessageTypeU.VideoHangUp.getValue()){

            String fp = p.getDataContent();
            Optional<Messages> messages =  messageRepository.findById(fp);
            Messages model =  messages.get();
            JSONObject jsonObject = JSONUtil.parseObj(model.getDataContent());
            jsonObject.set("end_time",System.currentTimeMillis());
            jsonObject.remove("answer");
            model.setDataContent(jsonObject.toJSONString(0));
            messageRepository.save(model);


            videoProgressFlags.remove(p.getTo());
            videoProgressFlags.remove(p.getFrom());
            return;
        }

        // 发起音视频
        if(p.getTypeu() == MessageTypeU.VideoOffer.getValue()){

            // 判断对方是否在忙线中，如果忙线，告诉我自己，对方在忙线
            if(videoProgressFlags.get(p.getTo()) != null){
                Protocal protocal = ProtocalFactory.createCommonData("","0", p.getFrom(),true,null, MessageTypeU.VideoBusyLine.getValue());
                try {
                    LocalSendHelper.sendData(protocal,null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return;
            }

            Messages messages = new Messages();
            BeanUtils.copyProperties(p,messages);
            Messages saveMessage =  messageRepository.save(messages);
            conversationUtil.createSelfConversation(messages);
            conversationUtil.createOtherPartyConversation(messages);
            conversationUtil.createMessageStatus(messages);




            String messageKey = saveMessage.getFp();
            ConcurrentHashMap map =  new ConcurrentHashMap<>();
            map.put(messageKey,new AtomicBoolean(false));
            // 添加特殊标识
            interruptedFlags.put(p.getFrom(),map);

            // TODO 问题点
            videoProgressFlags.put(p.getFrom(),p.getTo());

            ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();


            ScheduledFuture<?> future = null; // 明确初始化为 null


            try{
                scheduler.scheduleAtFixedRate(new Runnable() {
                    @Override
                    public void run() {
                        // state 1 发送中 state 2  对方已经接受  state 3 拒绝 state 4 未响应  5 对方已经取消
                        ConcurrentHashMap<String,AtomicBoolean> map1 = interruptedFlags.get(p.getFrom());
                        if(map1 != null){
                            if(!map1.get(messageKey).get()){
                                Optional<Messages> messagesDb =  messageRepository.findById(messageKey);
                                JSONObject jsonObject = JSONUtil.parseObj(messagesDb.get().getDataContent());
                                Integer state = jsonObject.getInt("state");
                                if(state == 2 || state == 3 || state ==4  || state == 5){
                                    ConcurrentHashMap map2 =  new ConcurrentHashMap<>();
                                    map.put(messageKey,new AtomicBoolean(true));
                                    interruptedFlags.put(p.getFrom(),map2);
                                    future.cancel(true);
                                }
                            }
                        }
                    }
                }, 0, 1, TimeUnit.SECONDS);
            }catch (Exception e){
                System.out.println(e);
            }

            scheduler.schedule(()-> {
                videoProgressFlags.remove(p.getFrom());
                ConcurrentHashMap<String,AtomicBoolean> map1 = interruptedFlags.get(p.getFrom());
                if(map1 != null){
                    if(!map1.get(messageKey).get()){
                        Optional<Messages> messagesDb =   messageRepository.findById(messageKey);
                        Messages messagesModel =  messagesDb.get();
                        JSONObject jsonObject = JSONUtil.parseObj(messagesModel.getDataContent());
                        jsonObject.set("state",4);
                        jsonObject.set("fp",messagesModel.getFp());
                        jsonObject.remove("offer");
                        String json = jsonObject.toJSONString(0);
                        messagesModel.setDataContent(json);
                        messageRepository.save(messagesModel);
                        // 告诉客户端没人接听，让客户端处理页面逻辑
                        if (OnlineProcessor.isOnline(messagesModel.getFrom())) {
                            MBObserver resultObserver = new MBObserver() {
                                public void update(boolean sucess, Object extraObj) {
                                }
                            };
                            Protocal protocal = ProtocalFactory.createCommonData(messages.getFrom(),"0", messagesModel.getFrom(),true,null, MessageTypeU.VideoNoResponse.getValue());
                            try {
                                LocalSendHelper.sendData(protocal,resultObserver);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                        if (OnlineProcessor.isOnline(messagesModel.getTo())) {
                            MBObserver resultObserver = new MBObserver() {
                                public void update(boolean sucess, Object extraObj) {
                                }
                            };
                            Protocal protocal = ProtocalFactory.createCommonData(messages.getFrom(),"0", messagesModel.getTo(),true,null, MessageTypeU.VideoNoResponse.getValue());
                            try {
                                LocalSendHelper.sendData(protocal,resultObserver);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                        interruptedFlags.remove(p.getFrom());
                    }
                }
            },10, TimeUnit.SECONDS);
            return;
        }

//        // 通用消息需要存储
//        Messages messages = new Messages();
//        BeanUtils.copyProperties(p,messages);
//        messages.setReadStatus(ReadStatus.UNREAD);
//        Messages saveMessage =  messageRepository.save(messages);
//        conversationUtil.createSelfConversation(messages);
//        conversationUtil.createOtherPartyConversation(messages);




    }



    @Override
    public boolean onTransferMessage_RealTimeSendFaild(Protocal p) {
        if(p.getTypeu() == MessageTypeU.VideoCancel.getValue()){
            // 出现一个问题，取消的时候是客户端向服务器发送了一个请求，并没有记录消息ID;
            String fp = p.getDataContent();
            Optional<Messages> messages =  messageRepository.findById(fp);
            Messages model =  messages.get();

            JSONObject dataContent = JSONUtil.parseObj(model.getDataContent());
            dataContent.set("state",5);
            model.setDataContent(dataContent.toJSONString(0));
            messageRepository.save(model);
            videoProgressFlags.remove(p.getFrom());
            return true;

        }

        return true;
    }






    @Override
    public void onTransferMessage4C2C_AfterBridge(Protocal p) {
        System.out.println();
    }
}
